perm filename DOER[NS,SYS]1 blob sn#104713 filedate 1974-06-01 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00019 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	Definitions.  The file DEFS must be assembled with this file.
C00005 00003		storage allocations
C00010 00004	DOER	NEXT	NEXT1
C00014 00005	LOOKBG
C00018 00006	COLECT	ENDIT
C00021 00007	WORD
C00025 00008	SORT0
C00027 00009	WRITE OUT NEW STORY IN TXT FILE   --	CATEG	CATEG0
C00032 00010	KEYW	DONE -- HERE WE LINK ALL THE STORY WORDS INTO THE DICTIONARY LISTS
C00038 00011	CHGNAM	INTRPT
C00040 00012	UUCODE	NXTDG	DOEXIT
C00042 00013	GETCH
C00044 00014	PUTCH	PUTSTR	PUT2DG
C00046 00015	MAKTIM
C00048 00016	TFLFIL	BADTFL
C00050 00017	CHKUFD	UFDENT	OPNUFD
C00053 00018	READAT	WRTDAT	WAIT
C00058 00019	NETWRK
C00059 ENDMK
C⊗;
;Definitions.  The file DEFS must be assembled with this file.
IFNDEF DEBUG <DEBUG←0>
	TITLE	DOER -- categorizer of AP stories
NOVIZ←←1 ;NON-ZERO MEANS STRIP VISUAL PAPER TAPE NUMBER FROM FRONT OF EACH STORY

F←0
A←1
B←2
C←3	;current character
D←4
E←5	;counter and temporary AC

L←6	;length of output text line.  Also, number of different keywords.
M←7
N←10

Q←11	;byte pointer into output story buffer
R←12	;temporary byte pointer

W←13	;W:Z are used as LOOKUP and ENTER block
X←14
Y←15
Z←16

P←17	;pdl pointer

;I/O channels

TO ←←0	;text output to .TXT file
TI ←←1	;text input from .TFL file
UFD←←2	;input from UFD
DAT←←3	;input from, and output to, .DAT file
;	storage allocations

IFN DEBUG <

LSYM←←2000
SYM:	BLOCK LSYM

>;END IFN DEBUG

DSK17:	17
	SIXBIT	/DSK/
	0

NTOBUF←←8		;number of records in story buffer--must hold whole story
LBUF←←200*NTOBUF
	BLOCK	200	;buffer for holding first part of record where story starts
BUF:	BLOCK	LBUF	;story buffer for collecting entire story
BUFEND←.-20		;address used for checking for story buffer overflow
TOCMD:	IOWD LBUF,BUF	;dump mode command for writing out new story in .TXT file
	0
DATCMD:	IOWD 1,DATA	;dump mode command for reading/writing .DAT goes here
	0

MAXIGN←←=30	;number of chars we are willing to ignore in from of story
TMPBUF:	BLOCK	2*MAXIGN/5

LORIGS←←5
ORIGS:	BLOCK	LORIGS	;list of sequence numbers referenced by current story
NORIGS:	-1		;number of entries in ORIGS, minus 1

LTEXT←←=600
TEXT:	BLOCK	LTEXT	;space for collecting and storing whole keywords together

LSORT←←=400
SORT:	BLOCK	LSORT	;list of sorted keywords: <link>,,<ptr into TEXT>

TFL:	0		;negative of number of .TFL filenames in table
LTFLST←←20
	BLOCK	LTFLST	;sorted list of .TFL filenames
TFLST:			;name of this block must follow the block
TFLNAM:	0		;name of current .TFL file open (zero if none)

NUBUFS←←2
UFDBUF:	BLOCK 203*NUBUFS;buffer space for reading UFD
UBUF:	BLOCK	3	;buffer header for reading UFD

NTIBUF←←2
TIBUF:	BLOCK 203*NTIBUF;buffer space for reading in .TFL files
IBUF:	BLOCK	3	;buffer header for reading .TFL files

LPDL←←30
PDL:	BLOCK	LPDL	;pushdown list

ERRBK:	SIXBIT	/DSK/	;block used to start up error-handling program
	ERRPRG		;program name goes here
	'DMP',,0
	1		;NORMAL CORE SIZE, RPG STARTUP (SA+1)
	APPPN
	APPPN

MONTH:	FOR MON IN (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)
<	ASCII	\MON \
>

SEQNBR:	0		;sequence number of current story
ORIGIN:	0		;pointer (in left half) to original of follow-up, if any
NEWSEQ:	0		;sequence number of next story (when already seen)
EOF:	0		;flag indicating whether there is an input file open
EOFDSP:	0		;address of routine to dispatch to on EOF from .TFL file
EOSDSP:	0		;address of routine to dispatch to on End Of Story
DATIN:	0		;flag telling if .DAT file has been read in
IGNORE:	0		;number of characters we will ignore looking for story
HNGTIM:	0		;number of times we have tried to do an ENTER and failed
HNGADR:	0		;return address of WAIT routine

APMIDNIGHT←←=21*=3600	;SU-AI time in seconds when AP goes to next day
ABSMINDATE←←7113	;7 JAN 74 in DAYCNT format
ABSMAXDATE←←7665	;4 JAN 75 in DAYCNT format
TODAY:	0		;today's date in DAYCNT format--used as file name
MINDATE:ABSMINDATE	;earliest reasonable date for TFL file, in DAYCNT format

APNAME:	SIXBIT /[DOER]/
;DOER	NEXT	NEXT1

DOER:	RESET
	MOVE	P,[IOWD LPDL,PDL]

	MOVEI	A,INTRPT	;get address of interrupt level module
	MOVEM	A,JOBAPR↑	;store it
	MOVSI	A,INTPTI!INTPAR	;enable interrupts on parity errors
	INTENB	A,		;	and pty input
	MOVSI	A,INTPTI
	INTGEN	A,		;generate a pty input int to set the job name
	MOVE	A,NBRFLR#	;get code indicating number of other DOERs
	JRST	.+2(A)
	EXIT			;ONE OTHER DOER ALREADY EXISTED
	UFATAL	102		;;;TWO OR MORE OTHER DOERS ALREADY EXISTED

	SETZM	TFL		;no .TFL filenames sorted yet
	SETZM	TFLNAM		;no .TFL file open yet
	SETZM	DATIN		;no .DAT file in core yet
	HRROS	JOBDDT↑		;make sure SAVE gets everybody

	INIT	TI,200		;prepare to read .TFL file in
	SIXBIT	/DSK/
	IBUF
	UFATAL	104		;;;CANT INIT DSK
	MOVEI	W,TIBUF
	MOVEM	W,JOBFF↑
	INBUF	TI,NTIBUF	;set up buffers in compiled in area

NEXT:	PUSHJ	P,TFLFIL	;open oldest .TFL file
	JRST  [	PUSHJ P,NETWRK	;no .TFL files, do anything needed with DC at CCA
		PUSHJ P,TFLFIL	;look again for .TFL files
		JRST DOEXIT	;still none--do any bookkeeping and exit
		JRST NEXT1]	;got one--process it
NEXT1:	MOVEI	W,NEXT
	MOVEM	W,EOFDSP	;set up dispatch address for EOF
	MOVEI	W,.+2
	MOVEM	W,EOSDSP	;set up dispatch address for END OF STORY
	SETZB	C,L		;clear current character, no chars on current line
	MOVEI	W,MAXIGN	;set up counter for maximum number of chars we
	MOVEM	W,IGNORE	;  will examine in searching for story beginning
	MOVE	Q,[POINT 7,TMPBUF] ;set up byte pointer for saving story read in
;LOOKBG

LOOKBG:	PUSHJ	P,GETCH		;look for beginning of a story
LOOKB3:	CAIN	C,"a"		;stories begin with "a109" followed by LF
	JRST	LOOKB2		;maybe we got one
	CAIE	C,LF		;(don't count LFs in limit of chars before beginning)
	SOSL	IGNORE		;have we looked far enough for a beginning
	JRST	LOOKBG		;no--look some more

	SETZ	C,		;yes--insert special beginning
	IDPB	C,Q		;mark end of text seen so far
	MOVE	Q,[POINT 7,BUF]	;set up byte pointer into story buffer
	MOVEI	R,=999
	MOVEM	R,SEQNBR	;give this story a special sequence number
	MOVEI	R,[ASCIZ /a999/]
	PUSHJ	P,PUTSTR	;put special sequence number into story
	PUSHJ	P,MAKTIM	;put time of categorization into story
	MOVEI	R,[ASCIZ /(Beginning missing.)
.../]
	PUSHJ	P,PUTSTR	;and add special message to beginning of story
	MOVEI	R,TMPBUF
	PUSHJ	P,PUTSTR	;copy text seen so far into story buffer
	JRST	COLECT		;and go collect rest of story

LOOKB2:	MOVEI	E,3		;look for 3 digits of seq nbr
	SETZ	D,		;calculate seq nbr in D
LOOKB1:	PUSHJ	P,GETCH
	CAIL	C,"0"
	CAILE	C,"9"		;is next char a digit?
	JRST	LOOKB3		;no--start over looking for beginning
	IMULI	D,=10
	ADDI	D,-"0"(C)	;add current digit into seq nbr value so far
	SOJG	E,LOOKB1	;found enough digits yet?
	PUSHJ	P,GETCH		;yes
	CAIE	C,LF		;three digits must be followed by LF
	JRST	LOOKB3		;must not be real beginning

	MOVEM	D,SEQNBR	;GOT BEGINNING OF STORY--SAVE SEQUENCE NUMBER
	ADD	Q,[070000,,0]	;BACK UP Q TO THE CR AFTER STORY NUMBER
	TLNE	Q,400000	;DID BYTE POINTER POSITION FIELD OVERFLOW?
	SUB	Q,[430000,,1]	;YES, ADJUST BP TO LAST BYTE IN PREVIOUS WORD
	DPB	E,Q		;mark end of seq nbr, and erase the CR
	MOVE	R,Q
	SUBI	R,1		;back up byte pointer R over seq nbr
	MOVE	Q,[POINT 7,BUF]	;set up byte pointer into story buffer
	PUSHJ	P,PUTST1	;copy ASCIZ string from TMPBUF into story buffer
COLEC0:	PUSHJ	P,MAKTIM	;put time of categorization into story
	INSKIP	1
	JRST	CONTIN
	OUTSTR	[ASCIZ/Manual stop.  CONTINUE will work./]
	CLRBFI
	EXIT	1,

;here is where we want to skip over the paper tape visual number (czzcxwwxyzzy)
CONTIN:
IFDEF NOVIZ<
IFN NOVIZ <
	PUSH	P,Q
	MOVEI	E,=22		;IF NEXT LINE LONGER THAT THIS, IS NOT VISUAL NUMBER
	PUSHJ	P,GETCH		;LOOK FOR A LF AT END OF VISUAL NUMBER
	CAIE	C,LF
	SOJG	E,.-2
	POP	P,D
	JUMPLE	E,.+2
	MOVE	Q,D		;HAVE FOUND LF IN TIME, DISCARD VISUAL NUMBER
>;END IFN NOVIZ
>;END IFDEF NOVIZ
;COLECT	ENDIT

COLECT:	MOVEI	E,ENDIT
	MOVEM	E,EOSDSP	;set up dispatch address for end of story found
	MOVEI	E,ENDIT1
	MOVEM	E,EOFDSP	;set up dispatch address for EOF
	SETZM	TMPBUF		;no new beginning seen yet.

COLEC3:	PUSHJ	P,GETCH		;look for beginning: "a109" LF
COLEC1:	CAIE	C,"a"
	JRST	COLEC3
	MOVEI	E,3
	SETZ	D,
COLEC2:	PUSHJ	P,GETCH
	CAIL	C,"0"
	CAILE	C,"9"
	JRST	COLEC1
	IMULI	D,=10
	ADDI	D,-"0"(C)
	SOJG	E,COLEC2
	PUSHJ	P,GETCH
	CAIE	C,LF
	JRST	COLEC1
	MOVEM	D,NEWSEQ
	ADD	Q,[067777,,-1]	;back up byte pointer over new story beginning seen
	PUSH	P,Q
	MOVEI	E,4
	MOVE	R,[POINT 7,TMPBUF]
	ILDB	C,Q
	IDPB	C,R		;save new story beginning in TMPBUF
	SOJG	E,.-2
	POP	P,Q
	JRST	ENDIT1

ENDIT:	SETZM	IBUF+2		;force next GETCH to get new record
	LDB	C,Q		;GET LAST CHAR IN STORY
	CAIE	C,LF		;SHOULD HAVE ENDED WITH LF
	JRST	ENDIT1		;DIDN'T END RIGHT
	MOVE	R,Q		;COPY BYTE PTR
	SUBI	R,2		;back up byte ptr 8 bytes
	IBP	R
	IBP	R
	ILDB	C,R		;see if story ended with CR,LF,SP,CR,LF,SP,CR,LF
	CAIE	C,CR
	JRST	ENDIT2		;NOPE
	ILDB	C,R
	CAIE	C,LF
	JRST	ENDIT2		;NOPE
	MOVE	Q,R		;set up byte ptr to end of real part of story
	JRST	ENDIT3		;NORMAL END OF STORY
ENDIT2:	LDB	C,Q		;get last char in story
ENDIT1:	CAIN	C,CR		;are we in the middle of a CRLF?
	PUSHJ	P,PUTLF		;yes--put in the LF
	MOVEI	R,[ASCIZ /...
(End missing.)
/]
	PUSHJ	P,PUTSTR	;put special message at end of story
ENDIT3:	SETZ	C,
	IDPB	C,Q		;put null byte at end of story
	TLNE	Q,760000	;and fill out whole word with nulls
	JRST	.-2
;WORD

	SETZM	TEXT
	MOVE	E,[TEXT,,TEXT+1]
	BLT	E,TEXT+LTEXT-1	;clear TEXT space
	SETOM	NORIGS		;no references to original stories yet
	SETZB	L,SORT		;clear keyword list header, length of list
	MOVE	Q,[POINT 7,BUF+4,20] ;set up byte pointer to beginning of story
				;don't categorize by seq nbr, time and date
	MOVE	R,[POINT 5,TEXT-1,34] ;set up byte pointer for collecting individual words

WORD:	ILDB	C,Q
WORD1:	JUMPE	C,CATEG		;zero means end of story--go do categorizing
	CAIGE	C,"A"		;look for beginning of a word--do we have a letter?
	JRST	WORD		;no
	CAIGE	L,LSORT-1	;too many keywords yet?
	CAML	R,[010500,,TEXT+LTEXT-=10] ;or run out of TEXT space yet?
	JRST	CATEG0		;yes to one of these--ignore remaining words
	ADDI	L,1		;count a new keyword
	HRRZM	R,SORT(L)	;store pointer to TEXT of this keyword
WORD3:	IDPB	C,R
	ILDB	C,Q		;get next char
	CAIL	C,"A"		;is it a letter?
	JRST	WORD3		;yes--here we go loop de loop
WORD2:	LDB	E,R		;no--see if perhaps have a story reference
	CAIE	E,"A"-100	;was last char an upper or lower case "A"?
	JRST	SORT0		;no--go sort this keyword into list
WORD5:	SETZ	D,		;collect sequence number in D
	MOVEI	E,3		;look for 3 digits
WORD4:	CAIL	C,"0"
	CAILE	C,"9"		;got a digit?
	JRST	WORD6A		;no--see if exactly 3 digits found
	IMULI	D,=10
	ADDI	D,-"0"(C)	;add digit into value so far
	ILDB	C,Q		;next char
	SOJGE	E,WORD4		;found enough digits yet?
WORD6A:	JUMPN	E,SORT0		;if E≠0 then wrong nbr of digits--sort word into list
WORD6:	CAMGE	D,SEQNBR	;see if this is a forward reference
	JRST	WORD7		;nope
	MOVE	E,SEQNBR
	CAIGE	D,20(E)		;if forward by more than 20, probably backward
	JRST	WORD7A		;forward reference, forget it
WORD7:	AOS	E,NORIGS	;found another story reference
	CAIL	E,LORIGS	;found too many already?
	SOSA	NORIGS		;yes--forget this one
	MOVEM	D,ORIGS(E)	;no--remember this one
WORD7A:	CAIE	C,"-"		;do we have several consecutive references?
	JRST	SORT0		;no--now insert keyword into sorted list
	ILDB	C,Q		;yes
	JRST	WORD5		;go back and get the next one
;SORT0

SORT0:	MOVEI	E,1
	ORM	E,(R)		;mark end of keyword in TEXT
	HRLI	R,010500	;advance byte pointer to end of word
	TDZA	D,D		;look at front of keyword list
SORT1:	MOVE	D,E
	HLRZ	E,SORT(D)	;get next word in list
	JUMPE	E,SORT4		;insert new word at end of list
	HRRZ	A,SORT(L)	;get ptr to text of new word
	HRRZ	B,SORT(E)	;get ptr to text of old word
SORT2:	MOVE	M,1(A)		;get a word of text of new word
	CAMLE	M,1(B)		;and compare against corresponding part of old word
	JRST	SORT1		;move on down keyword list
	CAME	M,1(B)
	JRST	SORT4		;insert right here in list
	TRNN	M,1		;keywords equal so far--at end of keyword?
	AOJA	A,[AOJA B,SORT2];no--get next part of each keyword
	MOVEI	E,1		;yes--keywords are the same
	JRST	SORT3A		;undo entries for new keyword
SORT3:	TDNE	E,(R)		;found end of previous keyword in TEXT?
	SOJA	L,WORD1		;yes--delete entry from sorted list
SORT3A:	SETZM	(R)		;no--clear TEXT for this word
	SOJA	R,SORT3		;back up a word in TEXT
SORT4:	HRLM	L,SORT(D)	;link new keyword into sorted list
	HRLM	E,SORT(L)
	JRST	WORD1
;WRITE OUT NEW STORY IN TXT FILE   --	CATEG	CATEG0

CATEG0:	ILDB	C,Q		;ADVANCE BYTE POINTER TO END OF STORY
	JUMPN	C,.-1
CATEG:	PUSHJ	P,READAT	;READ IN .DAT FILE (IF HAVEN'T ALREADY)

	OPEN	TO,DSK17
	UFATAL	106		;;;CANT OPEN DSK
	MOVE	W,TODAY
	MOVSI	X,'TXT'
	SETZ	Z,
	LOOKUP	TO,W
	UFATAL	110		;;;LOOKUP FAILED ON DAY'S .TXT FILE
	SETZB	Y,Z
	ENTER	TO,W		;open .TXT file in RA mode
	PUSHJ	P,WAIT		;can't right now--wait a bit and try again
	HRRZ	W,DATA+2	;PICK UP ADDRESS WITHIN TXT FILE WHERE STORY WILL GO
	SETZ	X,
	LSHC	W,-7		;RECORD NUMBER-1 INTO W, DISPLACEMENT INTO X
	JUMPE	X,CATEG1	;DOES STORY GO INTO MIDDLE OF A RECORD?
	ROT	X,7		;YES, READ FIRST PART OF RECORD
	MOVNI	X,(X)		;NEGATIVE AMOUNT OF OLD STUFF TO BE READ IN
	HRLI	X,BUF-1(X)	;ADDRESS FOR DUMP MODE INPUT COMMAND
	MOVSM	X,TOCMD
	USETI	TO,1(W)
	IN	TO,TOCMD	;READ IN A LITTLE OLD STUFF
	JRST	CATEG2
	UFATAL	112		;;;IN UUO FAILED TO READ IN END OF LAST STORY
CATEG1:	MOVEI	X,BUF-1		;NO OLD STUFF READ IN--SET UP OUTPUT DMP MODE ADDR
	MOVEM	X,TOCMD
CATEG2:	MOVEI	Q,1-BUF(Q)	;LENGTH OF STORY
	PUSH	P,DATA+2	;SAVE PTR TO PLACE FOR STORY
	ADDB	Q,DATA+2	;UPDATE POINTER TO FIRST FREE WORD IN TXT
	USETO	TO,1(W)
	LSH	W,7
	SUBI	W,(Q)
	HRLM	W,TOCMD
	OUT	TO,TOCMD	;write out new story
	JRST	.+2
	UFATAL	114		;;;OUT UUO FAILED TO WRITE OUT NEW STORY
	RELEAS	TO,		;done with .TXT file for now

;LINK NEW STORY TO EARLIER STORY IF NECESSARY
	HLRZ	E,DATA+2	;ptr to first free word in DAT
	MOVSM	E,ORIGIN
	SKIPGE	C,NORIGS
	JRST	CATEG5		;NO REFERENCES TO EARLIER STORY
	MOVNI	C,1(C)
	MOVSI	C,(C)		;AOBJN PTR TO STORY REFS
CATEG3:	MOVE	B,ORIGS(C)	;GET NEXT REF
	HLRZ	L,DATA		;PTR TO LAST STORY ENTRY
	JUMPE	L,CATEG5
CATEG7:	HRRZ	M,DATA+2(L)	;GET SEQ NBR OF PREV STORY
	CAIE	B,(M)		;SAME AS REF?
	JRST	CATEG4		;NO
	HLLZ	N,DATA+3(L)	;YES, GET ORIGINAL OF STORY TO LINK TO
	HLLZM	N,ORIGIN	;REMEMBER WHICH STORY TO USE IN CATEGORIZING
CATEG6:	HRRZ	N,DATA+3(L)	;ANY FOLLOW-UPS ALREADY?
	EXCH	L,N
	JUMPN	L,CATEG6	;IF SO, TRACE DOWN LIST TO LAST FOLLOW-UP
	HRRM	E,DATA+3(N)	;MAKE LAST FOLLOW-UP POINT TO NEW STORY
	JRST	CATEG5
CATEG4:	HLRZ	L,DATA(L)	;GET PTR TO NEXT PREV STORY
	JUMPN	L,CATEG7	;ANY MORE STORIES?
	AOBJN	C,CATEG3	;NO, ANY MORE STORY REFERENCES?
				;NO
;MAKE NEW ENTRY IN STORY LIST
CATEG5:	HLRZ	A,DATA		;PTR TO LAST STORY ENTRY
	HRLZM	A,DATA(E)	;MAKE NEW STORY ENTRY POINT TO PREV ONE
	HRRM	E,DATA(A)	;MAKE PREV STORY ENTRY POINT TO NEW ONE
	HRLM	E,DATA		;NEW VALUE FOR POINTER TO LAST STORY ENTRY
	POP	P,A		;RETRIEVE SAVED PTR TO NEW STORY IN TXT
	HLL	A,TOCMD		;GET DUMP MODE COMMAND NEEDED FOR STORY
	MOVEM	A,DATA+1(E)	; AND PLACE INTO STORY ENTRY
	HRRZ	A,SEQNBR	;GET NEW STORY'S SEQ NBR
	MOVEM	A,DATA+2(E)	; AND PLACE INTO STORY ENTRY
	MOVE	A,ORIGIN
	MOVEM	A,DATA+3(E)	;SET UP PTR TO ORIGINAL STORY
	ADDI	E,4		;NOTE WE USED UP FOUR MORE WORDS OF DAT
;KEYW	DONE -- HERE WE LINK ALL THE STORY WORDS INTO THE DICTIONARY LISTS

	HRRZ	D,DATA+1	;PTR TO FIRST DICT ENTRY
	HLRZ	C,SORT		;PTR TO FIRST WORD IN STORY
	JUMPE	C,DONE		;IF NO WORDS, TAKE IT EASY
KEYW:	MOVEI	B,DATA+1(D)	;SET UP ADDRESS OF TEXT OF DICT WORD
	SKIPGE	DATA(D)		; ADJUST THAT ADDRESS IF DICT ENTRY HAS EXTRA FIELDS
	ADDI	B,2
	HRRZ	A,SORT(C)	;ADDRESS OF TEXT OF WORD IN STORY
KEYW1:	MOVE	M,1(A)		;PICK UP 7 CHARS FROM STORY WORD
	CAME	M,(B)		;SAME AS THOSE OF DICT WORD?
	JRST	KEYW2		;NO
	TRNN	M,1		;YES, ARE WE TO THE END OF THE WORD?
	AOJA	A,[AOJA B,KEYW1];NO, ADVANCE BOTH POINTERS TO TEXT AND GO ON
	SKIPGE	A,1(B)		;YES. IS THIS DICT ENTRY FOR A COMMON ENGLISH WORD?
	JRST	KEYW9		;YES, IGNORE THIS WORD
	JUMPN	A,KEYW3		;NO, IS THERE AN OCCURRENCE ENTRY FOR THIS WORD?
	HLLZ	A,ORIGIN	;NO, THIS IS EASY.  PICK UP POINTER TO STORY
	MOVEM	A,1(B)		; AND DEPOSIT IN "COMPILED-IN" SPACE IN DICT ENTRY
	JRST	KEYW9

KEYW3:	HLLZ	M,ORIGIN	;PICK UP POINTER TO STORY CATEGORIZATION GOES WITH
	MOVEM	M,DATA(E)	;AND DEPOSIT IT IN NEW WORD-OCCURRENCE ENTRY
	MOVEI	A,1-DATA(B)	;SET UP POINTER TO FIRST W.O.
	HLLZ	N,DATA(A)	;PICK UP STORY INDEX OF FIRST STORY FOR THIS WORD
	CAMGE	N,M		;IS STORY BEING CATEGORIZED BEFORE FIRST STORY GIVEN?
	JRST	KEYW5A		;NO
	CAMG	N,M		;YES
	JRST	KEYW9		;THAT STORY ALREADY CATEGORIZED BY THIS WORD
	MOVE	N,DATA(A)	;PICK UP FIRST W.O. ENTRY
	MOVEM	N,DATA(E)	;AND PLACE IT IN NEW SLOT
	HRR	M,E		;MAKE NEW W.O. POINT TO OLD FIRST ONE
	MOVEM	M,DATA(A)	;PUT NEW W.O. IN "COMPILED-IN" SLOT
	AOJA	E,KEYW9

KEYW5:	HLLZ	N,DATA(A)
	CAML	N,M
	JRST	KEYW4
KEYW5A:	HRRZ	B,DATA(A)	;WALK DOWN LIST OF OCCURRENCES OF THIS DICT WORD
	JUMPE	B,KEYW6		;ARE WE AT THE END YET?
	HLLZ	N,DATA(B)
	CAML	N,M
	JRST	KEYW4A		;INSERT W.O. HERE IN LIST
	HRRZ	A,DATA(B)	;NO, PICK UP NEXT POINTER
	JUMPN	A,KEYW5		;AT END?
	MOVE	A,B		;YES
KEYW6:	HRRM	E,DATA(A)	;MAKE LAST WORD OCCURRENCE POINT TO NEW ONE
	AOJA	E,KEYW9		;NOTE WE USED UP ANOTHER WORD IN DAT FOR W.O.

KEYW4:	EXCH	A,B
KEYW4A:	CAMN	N,M
	JRST	KEYW9		;STORY ALREADY CATEGORIZED BY THIS KEYWORD
	HRRM	B,DATA(E)	;MAKE THIS NEW W.O. POINT TO NEXT ONE
	JRST	KEYW6

KEYW8:	HRRZ	D,DATA(D)	;ADVANCE TO NEXT DICT ENTRY
	JRST	KEYW

KEYW2:	CAML	M,(B)		;HAVE WE PASSED SPOT FOR THIS STORY WORD IN DICT?
	JRST	KEYW8		;NO, GET NEXT DICT ENTRY
	HLL	D,DATA(D)	;YES. PICK UP POINTER TO PREV DICT ENTRY
	MOVEM	D,DATA(E)	;PUT FORWARD/BACKWARD DICT POINTERS INTO NEW ENTRY
	HRLM	E,DATA(D)	;MAKE NEXT ENTRY POINT BACK TO NEW ONE
	MOVS	B,D		;GET POINTER TO PREV ENTRY
	HRRM	E,DATA(B)	;MAKE PREV ENTRY POINT FORWARD TO NEW ONE
	TRNE	M,1		;HAVE WE GOTTEN TO THE LAST CHARS IN STORY WORD?
	JRST	KEYW2A		;YES
	ADDI	A,1		;NO, EXAMINE NEXT 7 CHARS
	MOVEI	M,1		; UNTIL WE SEE END OF WORD (LOW ORDER BIT ON)
	TDNN	M,1(A)
	AOJA	A,.-1
KEYW2A:	HRRZ	B,SORT(C)	;PICK UP ADDRESS OF TEXT OF STORY WORD
	SUBI	A,-1(B)		;SUBTRACT FROM ADDRESS OF LAST PART TO GET LENGTH
	MOVSI	B,1(B)		;PUT BLT ORIGIN ADDRESS IN LEFT HALF OF B
	HRRI	B,DATA+1(E)	;WILL BLT TEXT INTO NEW DICT ENTRY
	ADDI	E,2(A)		;UPDATE POINTER TO FIRST FREE WORD IN DAT
	BLT	B,DATA-2(E)	;MOVE TEXT OF WORD
	HLLZ	A,ORIGIN	;PICK UP POINTER TO STORY BEING CATEGORIZED
	MOVEM	A,DATA-1(E)	;AND PUT INTO FIRST W.O. ENTRY FOR NEW DICT WORD
KEYW9:	HLRZ	C,SORT(C)	;ADVANCE TO NEXT WORD IN STORY
	JUMPN	C,KEYW		;ANY MORE WORDS IN STORY?
DONE:	HRLM	E,DATA+2	;STORE NEW VALUE FOR FIRST FREE WORD IN DAT
	PUSHJ	P,WRTDAT	;WRITE OUT DAT FILE
	SKIPE	A,TMPBUF
	JRST	DONE1
	SKIPE	EOF
	JRST	NEXT		;GET NEW INPUT FILE
	JRST	NEXT1		;CONTINUE READING OLD FILE

DONE1:	MOVEM	A,BUF
	MOVE	Q,[POINT 7,BUF,27]
	SETZB	C,L		;clear current char, number of chars on current line
	MOVE	A,NEWSEQ
	MOVEM	A,SEQNBR
	JRST	COLEC0
;CHGNAM	INTRPT

;interrupt level routine to set the job name
CHGNAM:	SETZ	A,			;zero out own job name
	SETNAM	A,
	SETOM	NBRFLR#			;initialize indicator to one other DOER
	MOVE	A,APNAME		;get DOER's name
	NAMEIN	A,
	JRST	.+2			;zero or multiple DOERs exist
	DISMIS				;one other DOER exists
	SETZM	NBRFLR			;set indicator to multiple DOERs
	CAIE	A,1			;check error code of NAMEIN
	DISMIS				;two or more other DOERs exist
	AOS	NBRFLR			;set indicator to no other DOERs
	MOVE	A,APNAME		;change job name
	SETNAM	A,
	MOVEI	A,INTPTI
	INTACM	A,			;disable interrupt used for name change
	DISMIS

;interrupt level module
INTRPT:	MOVS	A,JOBCNI↑	;get bit causing interrupt
	CAIN	A,INTPTI	;is this interrupt to set DOER's job name?
	JRST	CHGNAM		;yes.  do it
	CAIE	A,INTPAR
	DISMIS			;IGNORE STRANGE INTERRUPT
	UWAIT			;PARITY ERROR.  GIVE UP AND GO HOME
	JRST	2,@[.+1]	;get out of user-iot
	DEBREAK
	EXIT			;PARITY ERROR IN DOER
;UUCODE	NXTDG	DOEXIT

UUCODE:	0
	PUSH	P,A
	PUSH	P,B
	SETO	A,
	GETLIN	A
	AOJE	A,DET
	OUTSTR	[ASCIZ /
DOER error #/]
	HRRZ	A,40		;get error number
	PUSHJ	P,NXTDG		;TYPE OUT ERROR NUMBER
	POP	P,B
	POP	P,A
	EXIT	1,
	HALT	.
	JRST	@UUCODE

DET:	HLRZ	A,40		;GET UUO LH
	ANDI	A,777000	;MASK OUT ALL BUT OPCODE
	SETZ	B,
	CAIN	A,(<UWARN>)	;JUST A WARNING?
	MOVEI	B,14		;YES, START UP ERROR PROGRAM ON ANOTHER JOB
	HRRM	B,ERRBK+2	;STORE MODE BITS FOR SWAP
	MOVE	1,APNAME	;PASS JOB NAME IN AC 1
	MOVE	2,40		; AND ERROR UUO IN AC 2
	MOVEI	16,ERRBK
	SWAP	16,
	POP	P,B
	POP	P,A
	JRST	@UUCODE		;CONTINUE PROGRAM (HOPE WE HAVEN'T BEEN RESET)

NXTDG:	IDIVI	A,=8		;convert number in A to octal ASCII string
	HRLM	B,(P)
	JUMPE	A,.+2
	PUSHJ	P,NXTDG
	HLRZ	A,(P)
	ADDI	A,"0"
	OUTCHR	A
	POPJ	P,

DOEXIT:	EXIT	1,
	JRST	NEXT
;GETCH

GETCH:	SOSG	IBUF+2		;any more chars in buffer?
	IN	TI,		;no--next buffer please
	JRST	GETCH1
	STATO	TI,20000	;EOF?
	UFATAL	116		;;;DSK INPUT ERROR
	SETZB	W,Z
	RENAME	TI,W		;delete the file just read
	UFATAL	120		;;;CANT DELETE .TFL FILE
	SETOM	EOF		;NOTE WE HAVE NO INPUT FILE ANY MORE
	MOVE	P,[IOWD LPDL,PDL] ;yes--reset stack pointer
	JRST	@EOFDSP		;dispatch to EOF routine

GETCH1:	CAIN	C,CR		;was previous char a CR?
	JRST	POSTCR		;yes
	CAIN	C,LF		;no--was it a LF?
	JRST	POSTLF		;yes
	ILDB	C,IBUF+1	;no--get next char
	CAIN	C,LF		;next char a LF?
	JRST	PUTCRL		;yes--insert a CR before the LF
	JRST	PUTCH		;and save it

POSTCR:	ILDB	C,IBUF+1	;previous char was a CR--get next char
	CAIN	C,LF		;do we have a LF after the CR?
	JRST	PUTCH1		;yes--go store it
	PUSH	P,C		;no
	PUSHJ	P,PUTLF		;insert a LF
	POP	P,C
	CAIN	C,CR		;do we have a CR after the CRLF?
	JRST	LFCR		;yes--insert a space before the second CR
	JRST	PUTCH		;no--store the new char

POSTLF:	ILDB	C,IBUF+1	;previous char was a LF
	CAIN	C,CR
	JRST	LFCR		;LF followed by CR--insert a space
	CAIE	C,LF
	JRST	PUTCH		;nothing special here
	MOVEI	R,[ASCIZ / 
/]				;LF followed by LF--insert a space and a CR
	JRST	PUTSTR
LFCR:	MOVEI	R,[BYTE(7)" ",CR]
	JRST	PUTSTR
;PUTCH	PUTSTR	PUT2DG

PUTCH:	JUMPN	C,PUTCH2
	MOVEI	C,010700
	HRLM	C,IBUF+1	;skip to end of current input word
	MOVE	P,[IOWD LPDL,PDL] ;restore stack pointer
	JRST	@EOSDSP		;end-of-story routine

PUTCH2:	CAIL	L,=75		;line too long?
	CAIE	C," "		;yes.  do we have a space so that we can break here?
	JRST	PUTCH1		;no
PUTCRL:	MOVEI	C,CR		;yes--replace space with a CR and a LF
	PUSHJ	P,PUTCH1
PUTLF:	MOVEI	C,LF
PUTCH1:	IDPB	C,Q
	CAIN	C,LF		;got a LF?
	TDZA	L,L		;yes--note back at left margin
	ADDI	L,1		;no--note moved one more column to right
	CAME	Q,[POINT 7,BUFEND,34] ;running out of story buffer space?
	POPJ	P,		;no--all ok
	MOVE	P,[IOWD LPDL,PDL] ;yes
	JRST	ENDIT1		;put special ending on story

PUTSTR:	TLOA	R,440700	;make a byte pointer to string
	PUSHJ	P,PUTCH		;store a char
PUTST1:	ILDB	C,R		;next char
	JUMPN	C,.-2		;null?
	LDB	C,Q		;get last character put out
	POPJ	P,		;yes--done

PUT2DG:	IDIVI	A,=10		;routine to convert number in A to 2 digits of ASCII
	ADDI	A,"0"
	IDPB	A,Q
	ADDI	B,"0"
	IDPB	B,Q
	POPJ	P,
;MAKTIM

MAKTIM:	MOVEI	D," "
	IDPB	D,Q
	IDPB	D,Q		;two spaces before the time
	OUTFIV	BUF	;TYPE OUT SEQ NUMBER
	ACCTIM	A,		;get date and time
	PUSH	P,A		;and save for printing date later
	ANDI	A,-1		;clear date
	IDIVI	A,=60		;convert time to minutes
	IDIVI	A,=60		;convert to hours
	PUSH	P,B		;save minutes
	PUSHJ	P,PUT2DG	;print hours
	POP	P,A
	PUSHJ	P,PUT2DG	;print minutes
	IDPB	D,Q
	IDPB	D,Q		;two spaces after time and before date
	HLRZ	A,(P)		;retrieve date
	IDIVI	A,=31
	MOVEM	A,(P)		;save months
	MOVEI	A,1(B)
	PUSHJ	P,PUT2DG	;print day of month
	IDPB	D,Q		; and one space
	POP	P,A
	IDIVI	A,=12
	MOVEI	R,MONTH(B)
	PUSHJ	P,PUTSTR	;print month and a space
	ADDI	A,=64
	PUSHJ	P,PUT2DG	;print year
	MOVEI	D,CR		;put CRLF after date
	IDPB	D,Q
	MOVEI	D,LF
	IDPB	D,Q
	POPJ	P,
;TFLFIL	BADTFL

TFLFI1:	UWARN	122		;;;LOOKUP FAILED ON .TFL FILE
TFLFIL:	AOSLE	X,TFL		;any more .TFL files in sorted list?
	JRST	CHKUFD		;no--see if any listed in UFD
	MOVE	W,TFLST-1(X)	;yes--get name of next one
	MOVSI	X,'TFL'
	SETZ	Z,
	LOOKUP	TI,W
	JRST	TFLFI1

	HLRZ	X,W		;DATE INTO X
	MOVEI	Y,(W)		;TIME INTO Y
	CAIL	Y,APMIDNIGHT	;AFTER MIDNIGHT AP TIME?
	ADDI	X,1		;YES--NEXT DAY
	CAMGE	X,MINDATE	;REASONABLE DATE?
	JRST	BADTFL		;NO
	MOVEM	X,MINDATE	;YES

	ACCTIM	Z,		;GET CURRENT DATE/TIME
	HLRZ	Y,Z		;DATE INTO Y
	DAYCNT	Y,		;CONVERT TO DAYCNT FORMAT
	CAIL	Y,ABSMINDATE	;REASONABLE DATE?
	CAILE	Y,ABSMAXDATE
	UFATAL	124		;;;SYSTEM DATE SCREWED UP
	ANDI	Z,-1		;TIME ONLY IN Z
	CAIL	Z,APMIDNIGHT	;IS IT AFTER MIDNIGHT AP TIME?
	ADDI	Y,1		;YES--PRETEND NEXT DAY HERE
	CAIG	X,(Y)		;IS FILE'S DATE LATER THAN TODAY?
	CAMGE	Y,TODAY		;HAS TODAY GONE BACKWARDS?
	UFATAL	126		;;;SYSTEM DATE IS SCREWED UP
	MOVEM	Y,TODAY
	SETZM	EOF		;NOTE THAT WE HAVE AN AVAILABLE INPUT FILE

CPOPJ1:	AOS	(P)
CPOPJ:	POPJ	P,

BADTFL:	UWARN	130		;;;BAD FILENAME IN .TFL FILE
	MOVSI	X,'BFL'
	SETZM	Y,Z
	RENAME	TI,W		;RENAME .BFL←.TFL
	UFATAL	132		;;;CANT RENAME BAD .TFL FILE TO .BFL
	JRST	TFLFIL
;CHKUFD	UFDENT	OPNUFD

OPNUFD:	INIT	UFD,210
	SIXBIT	/DSK/
	UBUF
	UFATAL	134		;;;CANT INIT DSK
	MOVEI	W,UFDBUF
	MOVEM	W,JOBFF↑
	INBUF	UFD,NUBUFS	;SET UP BUFFERS FOR UFD IN SPECIAL BLOCK

	MOVE	W,[APPPN]
	MOVSI	X,'UFD'
	MOVE	Z,['  1  1']
	LOOKUP	UFD,W
	UFATAL	136		;;;CANT LOOK UFD
	POPJ	P,

CHKUFD:	PUSHJ	P,OPNUFD
	MOVEI	Z,'TFL'		;LOOK FOR FILES WITH EXTENSION .TFL
	PUSHJ	P,UFDENT
	JUMPE	W,CPOPJ
	MOVEM	W,TFLST-1
	SETOB	Y,TFL		;we have one file in sorted list so far
CHKUF1:	PUSHJ	P,UFDENT
	JUMPE	W,TFLFIL
	CAMLE	W,TFLST(Y)	;move up sorted list til find place to insert
	AOJL	Y,.-1
	MOVEI	X,TFLST-1
	ADD	X,TFL		;address to BLT to to make room for inserted file
	HRLI	X,1(X)		;BLT each entry down one word
	BLT	X,TFLST-2(Y)	;move list (Y points to first one not moved)
	MOVEM	W,TFLST-1(Y)	;insert new entry
	SOS	Y,TFL		;note list is now one entry longer
	CAMLE	Y,[-LTFLST]	;is list too long?
	JRST	CHKUF1		;no
	halt			;yes--we need to BLT whole list upwards
	MOVEI	Y,LTFLST-1
	MOVE	W,TFLST-LTFLST-1(Y)
	MOVEM	W,TFLST-LTFLST(Y)
	SOJG	Y,.-2
	MOVNI	Y,LTFLST-1
	MOVEM	Y,TFL
	JRST	CHKUF1

;ROUTINE TO FIND NEXT UFD ENTRY WITH EXTENSION SPECIFIED IN RIGHT HALF OF AC Z
;RETURNS NEXT FILE NAME IN W, OR ZERO IF NO MORE FILES WITH GIVEN EXTENSION
UFDENT:	SOSLE	UBUF+2
	JRST	UFDEN2
	IN	UFD,
	JRST	UFDEN1
	STATO	UFD,20000	;EOF?
	UFATAL	140		;;;INPUT DSK ERROR FROM READING UFD
	RELEAS	UFD,
	SETZ	W,		;yes--note no more UFD entries
	POPJ	P,
UFDEN1:	MOVE	W,UBUF+2
	ASH	W,-2		;divide UFD buffer word count by 4
	MOVEM	W,UBUF+2
UFDEN2:	ILDB	W,UBUF+1	;PICK UP FILE NAME
	ILDB	X,UBUF+1	;AND EXTENSION
	AOS	UBUF+1		;SKIP THIRD AND FOURTH WORDS OF EACH UFD ENTRY
	AOS	UBUF+1
	JUMPE	W,UFDENT	;ZERO FILE NAME MEANS ENTRY NOT IN USE
	HLRZ	X,X		;PUT EXTENSION IN RIGHT HALF
	CAIE	X,(Z)		;GOT EXTENSION WE ARE LOOKING FOR?
	JRST	UFDENT		;NO
	POPJ	P,		;YES
;READAT	WRTDAT	WAIT

READAT:

IFN DEBUG, <
	HRLZ	W,JOBSYM↑	;GET PTR TO SYMBOL TABLE
	CAMN	W,[SYM,,0]	;HAVE WE MOVED SYMBOLS ALREADY?
	JRST	NOMOVE		;YES
	HRRI	W,SYM		;ADDRESS OF NEW LOC FOR SYMBOL TABLE
	HRRM	W,JOBSYM	;MAKE NEW PTR TO SYMBOL TABLE
	HLRE	X,JOBSYM	;GET LENGTH OF SYMBOL TABLE
	MOVN	X,X		;AND MAKE IT POSITIVE
	CAILE	X,LSYM
	UFATAL	142		;;;NOT ENOUGH ROOM FOR MOVED SYMBOL TABLE
	ADDI	X,-1(W)		;CALCULATE ADDRESS OF LAST WORD
	BLT	W,(X)		;MOVE IT
NOMOVE:
>

	MOVE	W,TODAY
	CAMN	W,DATIN		;HAS .DAT ALREADY BEEN READ IN?
	JRST	READA4
	MOVEM	W,DATIN		;NO, BUT ITS WILL HAVE BEEN IN A SEC
	OPEN	DAT,DSK17
	UFATAL	144		;;;CANT OPEN DSK
	MOVSI	X,'DAT'
	SETZ	Z,
	LOOKUP	DAT,W
	JRST	READA1
READA2:
	HLLM	Z,DATCMD	;set up word count for reading .DAT
	HRRZ	Y,DATCMD	;get address where .DAT file will go
	MOVS	Z,Z		;negative length of .DAT file into Z
	SUB	Y,Z		;address of last word in .DAT file
	ADDI	Y,2000*4	;MAKE SURE WE HAVE ROOM TO SPARE
	CAMG	Y,JOBREL↑	;already have enough core?
	JRST	READA3		;yes
	CORE	Y,		;get enough
	UFATAL	146		;;;CANT GET ENOUGH CORE
READA3:	IN	DAT,DATCMD
	POPJ	P,
	UFATAL	150		;;;DSK INPUT ERROR READING .DAT FILE

READA4:	HLRZ	Y,DATA+2	;PICK UP POINTER TO FIRST FREE WORD IN DAT
	ADDI	Y,DATA+2000*4	;ADD 4K OF SPARE ROOM
	CAMG	Y,JOBREL↑	;ALREADY GOT ENOUGH ROOM?
	POPJ	P,		;YES, RELAX
	CORE	Y,		;NO, GET ENOUGH
	UFATAL	152		;;;CANT GET ENOUGH CORE
	POPJ	P,

READA1:	ANDI	X,-1
	JUMPE	X,.+2		;.DAT FILE NON-EXISTENT?
	UFATAL	154		;;;LOOKUP ERROR FOR .DAT FILE
	OPEN	TO,DSK17	;YES
	UFATAL	156		;;;CANT INIT DSK
	MOVSI	X,'TXT'
	MOVSI	Y,077000
	SETZ	Z,
	ENTER	TO,W		;CREATE .TXT FILE
	UFATAL	160		;;;CANT ENTER NEW .TXT FILE
	RELEAS	TO,		;WITH NOTHING IN IT
	MOVSI	W,'INI'
	MOVSI	X,'DAT'
	SETZ	Z,
	LOOKUP	DAT,W		;GET INITIAL COPY OF .DAT FILE FROM 'INI.DAT'
	UFATAL	162		;;;CANT LOOKUP INI.DAT FILE
	JRST	READA2

WRTDAT:	CLOSE	DAT,
	MOVE	W,TODAY
	MOVSI	X,'DAT'
	MOVSI	Y,077000
	SETZ	Z,
	ENTER	DAT,W
	UFATAL	164		;;;CANT ENTER .DAT FILE
	HLRZ	W,DATA+2	;GET POINTER TO FIRST FREE WORD IN DAT
	SETZM	DATA(W)		;ZERO THE FIRST FREE WORD
	MOVNI	W,1(W)		;get negative (word count + 1) of .DAT file to write
	HRLM	W,DATCMD	;and store in dump mode command
	OUT	DAT,DATCMD
	JRST	.+2
	UFATAL	166		;;;DISK OUTPUT ERROR WRITING .DAT FILE
	CLOSE	DAT,
	POPJ	P,

WAIT:	EXCH	A,(P)		;get return address
	SUBI	A,2		;and make into real return address
	MOVEM	A,HNGADR	;and store
	AOS	A,HNGTIM	;count another time hung
	CAIN	A,=20
	UWARN	170		;;;COULD NOT OPEN .TXT FILE FOR 3 1/2 minutes
	CAIN	A,=40
	UWARN	172		;;;COULD NOT OPEN .TXT FILE FOR 13 2/3 minutes
	CAIL	A,=60
	UFATAL	174		;;;COULD NOT OPEN .TXT FILE FOR 30 1/2 minutes
	SLEEP	A,		;sleep a little longer each time
	POP	P,A
	JRST	@HNGADR
;NETWRK

NETWRK:	POPJ	P,

	VAR
	LIT
DATA:	0			;.DAT FILE WILL GO HERE

	END	DOER